from BeautifulSoup import BeautifulSoup as Soup

def rip_table_from_string(text):
    """
    text: A string that stores HTML. Will return the entire text of the
    very first table it finds down to it's end tag.
    """
    begin_table = text.find("<table")
    if begin_table == -1:
        return None

    remaining = 1
    table_found = begin_table
    table_skip = 6

    while (remaining > 0):
        next_start = text.find("<table", table_found + table_skip)
        next_end = text.find("</table", table_found + table_skip)

        if next_start == -1:
            table_found = next_end
        elif next_end == -1:
            table_found = next_start
        else:
            table_found = min(next_start, next_end)
        
        if text[table_found+1] == '/':
            remaining -= 1
        else:
            remaining += 1

    return text[begin_table:table_found + 8]

class DiveError(Exception):
    def __init__(self, error, path, completed):
        self.path = path
        self.completed = completed
        self.error = error

    def __str__(self):
        return "During path: %s, during index %d, an error occured: %s\n" %\
            (self.path, self.completed, self.error)
        


def dive_into_soup(soup, content_navigation):
    s = soup

    for index, content in enumerate(content_navigation):
        try:
            s = s.contents[content]
        except IndexError as e:
            raise DiveError(e, content_navigation, index)

    return s

def find_path_to_text(soup, text):
    """
    soup: A BeautifulSoup soup object.
    text: The text to find. Should be one place in the html.

    Will return an array of contents indexes that, if used in succession,
    can be used to retrieve the text in the found location using similar
    soups.

    If the text is not found, returns None.
    """
    text = unicode(text, encoding='utf-8')

    if unicode(soup).find(text) == -1:
        return None

    path = []
    current = soup

    while current.find(text) != 0 and len(current.contents) > 0:
        old = current
        for index in range(len(current.contents)):
            if unicode(current.contents[index]).find(text) != -1:
                path.append(index)
                current = current.contents[index]
                break

        # Make sure we 'moved' foreward. If we didn't we didn't find the string
        # lower, even if there are lower contents (possible if searching for text
        # with HTML inside of it.
        if old == current:
            break

        if not hasattr(current, 'contents'):
            break


    return path

def save_as_test(soup, filename):
    """
    Saves the html for a soup to a file so that it can be used in testing
    """
    f = open(filename, "w")
    f.write(unicode(soup).encode('utf-8'))
    f.close()

def load_as_test(filename):
    """
    Loads a test file into a soup for use in testing.
    """
    f = open(filename, "r")
    lines = ''.join(f.readlines())
    s = Soup(lines, fromEncoding='utf-8')

    return s



    
    

